package com.amtf.datafile;

import java.io.File;
import java.io.IOException;
import java.util.List;

import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.input.SAXBuilder;

public class DataRecordDefinition {
	private String _name = "";
	private Class<DataRecord> _dataRecordClass = DataRecord.class;
	private char _delimiter = ',';
	private char _smartQuote = '"';
	private String _rowTerminator = "\r\n";
	private String _encoding = "UTF-8";
	private boolean _firstRowTitle = true;
	private boolean _columnCountNGException = false;
	private DataColumnDefinition[] _columnDefinition = new DataColumnDefinition[0];

	public static final DataRecordDefinition DEFAULT_CSV_DEFINITION = new DataRecordDefinition("UTF-8", true, ',', '"');
	public static final DataRecordDefinition DEFAULT_TSV_DEFINITION = new DataRecordDefinition("UTF-8", true, '\t', '"');

	@Override
	public DataRecordDefinition clone() {
		DataRecordDefinition cloneDef = new DataRecordDefinition("UTF-8", false, ',', '"');

		cloneDef._name = this._name;
		cloneDef._dataRecordClass = this._dataRecordClass;
		cloneDef._delimiter = this._delimiter;
		cloneDef._smartQuote = this._smartQuote;
		cloneDef._rowTerminator = this._rowTerminator;
		cloneDef._encoding = this._encoding;
		cloneDef._firstRowTitle = this._firstRowTitle;
		cloneDef._columnCountNGException = this._columnCountNGException;
		cloneDef._columnDefinition = new DataColumnDefinition[this._columnDefinition.length];
		for (int i = 0; i < this._columnDefinition.length; i++) {
			cloneDef._columnDefinition[i] = this._columnDefinition[i].clone();
		}

		return cloneDef;
	}

	// public DataRecordDefinition() {
	// }

	public DataRecordDefinition(String encoding, boolean firstRowTitle, char columnDelimiter, char smartQuote) {
		_delimiter = columnDelimiter;
		_smartQuote = smartQuote;
		_encoding = encoding;
		_firstRowTitle = firstRowTitle;
	}

	public DataRecordDefinition(String encoding, boolean firstRowTitle, char columnDelimiter, char smartQuote, Class<DataRecord> dataRecordClass, List<DataField> columnDefs) {
		_delimiter = columnDelimiter;
		_smartQuote = smartQuote;
		_encoding = encoding;
		_firstRowTitle = firstRowTitle;

		if (dataRecordClass != null) {
			_dataRecordClass = dataRecordClass;
		}

		if (columnDefs != null) {
			this._columnDefinition = new DataColumnDefinition[columnDefs.size()];
			for (int i = 0; i < columnDefs.size(); i++) {
				this._columnDefinition[i] = columnDefs.get(i).getDefinition().clone();
			}
		}
	}

	public DataRecordDefinition(String formatDefineFile) throws ClassNotFoundException, JDOMException, IOException {
		this(new File(formatDefineFile));
	}

	public DataRecordDefinition(File formatDefineFile) throws ClassNotFoundException, JDOMException, IOException {
		Document doc = null;
		SAXBuilder builder = new SAXBuilder(false);
		doc = (Document) builder.build(formatDefineFile);

		Element recordDef = doc.getRootElement().getChild("RecordDefinition");
		if (recordDef == null) {
			throw new IOException("Record definition format invalid!");
		}

		String name = recordDef.getAttributeValue("name");
		if (name != null && !"".equals(name)) {
			_name = name;
		} else {
			_name = formatDefineFile.getCanonicalPath();
		}

		String delimiter = recordDef.getAttributeValue("columnDelimiter");
		if (delimiter != null && !"".equals(delimiter)) {
			_delimiter = delimiter.charAt(0);
		}

		String smartQuote = recordDef.getAttributeValue("smartQuote");
		if (smartQuote != null) {
			if ("false".equalsIgnoreCase(smartQuote) || "".equals(smartQuote)) {
				_smartQuote = ' ';
			} else {
				_smartQuote = smartQuote.charAt(0);
			}
		}

		String rowTerminator = recordDef.getAttributeValue("rowTerminator");
		if (rowTerminator != null && !"".equals(rowTerminator)) {
			_rowTerminator = rowTerminator;
		}

		Attribute attrib = recordDef.getAttribute("columnCountNGException");
		if (attrib != null) {
			_columnCountNGException = attrib.getBooleanValue();
		}

		String clsName = recordDef.getAttributeValue("dataRecordClass");
		if (clsName != null && !"".equals(clsName)) {
			_dataRecordClass = (Class<DataRecord>) Class.forName(clsName);
		}

		attrib = recordDef.getAttribute("firstRowTitle");
		if (attrib != null) {
			_firstRowTitle = attrib.getBooleanValue();
		}

		String encoding = recordDef.getAttributeValue("encoding");
		if (encoding != null && !"".equals(encoding)) {
			_encoding = encoding;
		}

		int i = 0;
		List<Element> es = recordDef.getChildren();
		this._columnDefinition = new DataColumnDefinition[es.size()];
		for (Element e : es) {
			this._columnDefinition[i] = new DataColumnDefinition(e, this);
			if (this._columnDefinition[i].getName().length() == 0) {
				this._columnDefinition[i].setName("Column " + i);
			}
			i++;
		}
	}

	public DataColumnDefinition getDefaultColumnDefinition() {
		if (_columnDefinition.length > 0) {
			return _columnDefinition[_columnDefinition.length - 1];
		} else {
			return new DataColumnDefinition(this);
		}
	}

	public DataColumnDefinition getColumnDefinition(int index) {
		return _columnDefinition[index];
	}

	public DataColumnDefinition[] getColumnDefinitions() {
		return _columnDefinition;
	}

	public boolean isFirstRowTitle() {
		return _firstRowTitle;
	}

	public char getColumnDelimiter() {
		return _delimiter;
	}

	public boolean isColumnCountNGException() {
		return _columnCountNGException;
	}

	public DataRecord newDataRecordInstance() {
		try {
			return (DataRecord) _dataRecordClass.getConstructors()[0].newInstance(this);
		} catch (Throwable e) {
			// e.printStackTrace();
		}

		return null;
	}

	public String getDefinitionFile() {
		return this._name;
	}

	public String getEncoding() {
		return _encoding;
	}

	public String getRowTerminator() {
		return _rowTerminator;
	}

	public void setColumnDelimiter(char delimiter) {
		this._delimiter = delimiter;
	}

	public char getSmartQuote() {
		return _smartQuote;
	}

	public void setSmartQuote(char smartQuote) {
		this._smartQuote = smartQuote;
		for (DataColumnDefinition dcd : _columnDefinition) {
			dcd.setQuote(smartQuote);
		}
	}

	public void setRowTerminator(String rowTerminator) {
		this._rowTerminator = rowTerminator;
	}

	public void setEncoding(String encoding) {
		this._encoding = encoding;
	}

	public void setFirstRowTitle(boolean firstRowTitle) {
		this._firstRowTitle = firstRowTitle;
	}

	public String getName() {
		return _name;
	}

}
